#pragma once

#include <stdlib.h>

/////////////////////////////////////////////////////////////////
// Basic Types
/////////////////////////////////////////////////////////////////

#define null 0
#define true 1
#define false 0

#define bool char
//typedef char					bool;
typedef wchar_t					wchar;
typedef char					int8;
typedef short					int16;
typedef int						int32;
typedef long					int64;

typedef unsigned char           uint8;
typedef unsigned short			uint16;
typedef unsigned int            uint32;
typedef unsigned long			uint64;

typedef float					float32;
typedef double					float64;

typedef void (FreeObject)(void* oObject);

/////////////////////////////////////////////////////////////////
// List
/////////////////////////////////////////////////////////////////

typedef struct String
{
	uint32 length;
	uint32 capacity;
	int32 hashcode;
	wchar* value;
}String;

void StringDelete(String* sString);

String* StringCreate(uint32 iInitialCapacity);
String* StringCreateFromChar(const char* sString);
String* StringCreateFromString(String* sString);

int32 StringHashCode(String* sString);
int32 StringCompare(String* sString1, String* sString2);

void StringAppend(String* sString, wchar* sValue, ...);
void StringAppendXml(String* sString, wchar* sValue);
void StringAppendSpace(String* sString, uint32 iCount);
void StringAppendCharacter(String* sString, int32 iValue);


int32 WCharLength(wchar* sString);

/////////////////////////////////////////////////////////////////
// List
/////////////////////////////////////////////////////////////////

/*
The linked list is a basic data structure that houses any list of objects and provied
list functions for adding, removing and accessing. This is also the basic data type for
stacks and queues.
*/
typedef struct ListItem
{
	void* value;
	struct ListItem* next;
	struct ListItem* prevoius;
}ListItem;

typedef struct List
{
	uint32 size;
	ListItem* first;
	ListItem* last;
}List;


List* ListCreate();
void ListFree(List* pList, FreeObject* fFree);
void* ListAdd(List* pList, void* pObject);


/////////////////////////////////////////////////////////////////
// Reader
/////////////////////////////////////////////////////////////////

#define EOF (-1)

/*
The Reader is a char buffer that keeps track of current read location, line number, and column
by providing read, peek and skip function to access the stored data. The reader facilitates 
parsing and provides line and column number information for error/message tracking ducing parsing.
*/
typedef struct Reader
{
	char* buffer;		//The char buffer that contains the data to be red.
	char* bufferEnd;	//Points to the end of the buffer, mainly used to speed up EOF checks.
	char* current;		//Points to the current red location within the buffer.
	uint32 line;		//Holds the current line number being red.
	uint32 column;		//Holds the current column number being red.

}Reader;

/* Frees the reader and the containing buffer from memory */
void ReaderFree(Reader* pReader);

/* Create a new reader structure and allocates a buffer of the specified length */
Reader* ReaderCreate(uint32 iLength);

/* Creates a new reader and populates the buffer with the specified file content. If error reading
file then returns null. */
Reader* ReaderCreateFromFile(const char* sFilePath);

/* Peeks onto any character in the buffer. Returns EOF if specified indes is invalid. 
This function does not check of negative index and so it is up to the caller to insure validity.
The peek functions are defines to improve performance.
*/
#define ReaderPeek(pReader) ((pReader)->current < (pReader)->bufferEnd ? *(pReader)->current : EOF)
#define ReaderPeekAt(pReader, iIndex) (((pReader)->current + (iIndex)) < (pReader)->bufferEnd ? *((pReader)->current + (iIndex)) : EOF)

/* Reads the next character off the buffer and updates the line and column number. */
int32 ReaderRead(Reader* pReader);

/* Skips the specified number of characters and updates the line and column number. */
void ReaderSkip(Reader* pReader, uint32 iSkip);
int32 ReaderSkipUntilChar(Reader* pReader, int32 iChar);
int32 ReaderReadUntilChar(Reader* pReader, String* sBuffer, int32 iChar);
int32 ReaderReadUntilString(Reader* pReader, String* sBuffer, wchar *sToken);


/////////////////////////////////////////////////////////////////
// Message
/////////////////////////////////////////////////////////////////

typedef enum {ERROR = -1, WARNING = 1, MESSAGE = 0 } MessageType;

/*
A message can be an error, warning or message. It contains the line and column number where the
message occured along with extra information to be used as part of the display message.

Tipically the Message Handler is a list of raised errors, warnings and messages. The ability to hold more than one 
error message allows the application to provide more information in a single run.

Some message are faital and some are recoverable. It is up to the program to know when to stop.
*/
typedef struct Message
{
	int32 code;
	int32 line;
	int32 column;
	char message[256];
	char parameter[128];
	MessageType type;
}Message;

Message* MessageCreate(MessageType iType, int32 code, int32 iLine, int32 iColumn, char* sParameter);
void MessageFree(Message* pMessage);


/////////////////////////////////////////////////////////////////
// XML
/////////////////////////////////////////////////////////////////

#define ELEMENT_NODE		1
#define ATTRIBUTE_NODE		2
#define TEXT_NODE			3
#define COMMENT_NODE		5
#define DOCUMENT_NODE		6

typedef struct XmlNode
{
	int32 nodeType;

    String* nodeName;
	String* nodeValue;

	struct XmlNode* lastChild;
	struct XmlNode* firstChild;

	struct XmlNode* parentNode;
	struct XmlNode* nextSibling;
	struct XmlNode* previousSibling;

	struct XmlNode* lastAttribute;
	struct XmlNode* firstAttribute;

}XmlNode, XmlAttribute, XmlDocument, XmlElement, XmlComment, XmlCData, XmlText;

void XmlDeleteNode(XmlNode* pNode, bool bDeleteChildren);
XmlNode* XmlCreateNode(int32 iType, String* sName, String* sValue);

XmlNode* XmlAppendChild(XmlNode* pParent, XmlNode* pChild);
XmlNode* XmlRemoveChild(XmlNode* pParent, XmlNode* pChild);
XmlNode* XmlInsertChild(XmlNode* pParent, XmlNode* pChild, XmlNode* pBeforeChild);
XmlNode* XmlReplaceChild(XmlNode* pParent, XmlNode* pNewChild, XmlNode* pOldChild);

void XmlRemoveAttribute(XmlElement* pElement, String* sName);
XmlAttribute* XmlRemoveAttributeNode(XmlElement* pElement, XmlAttribute* pAttribute);

const String* XmlGetAttribute(XmlElement* pElement, String* sName);
XmlAttribute* XmlGetAttributeNode(XmlElement* pElement, String* sName);

XmlAttribute* XmlSetAttribute(XmlElement* pElement, String* sName, String* sValue);
XmlAttribute* XmlSetAttributeNode(XmlElement* pElement, XmlAttribute* oNode);

XmlNode* XmlAppendNode(XmlNode* pParent, XmlNode* pNode, XmlNode** pFirst, XmlNode** pLast);
XmlNode* XmlRemoveNode(XmlNode* pParent, XmlNode* pNode, XmlNode** pFirst, XmlNode** pLast);

String* XmlSerialize(XmlElement* pRoot, String* sBuffer, bool bIndent);
XmlNode* XmlParse(XmlNode* pDocument, Reader* pReader, bool bNormalize);
